#include "liveserver.h"
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <cv.h>
#include "trace.h"

LiveServer::LiveServer(const char *hostname, LocalCapture *capture,
                       const unsigned int port, const unsigned int fps) :
        HOSTNAME(hostname), LIVEPORT(port), FPS(fps)
{
    isRunning = false;
    isInit = false;
    m_Capture = capture;
}

void LiveServer::startLiveServer()
{
    isInit = true;
    boost::thread netTrd(boost::bind(&LiveServer::localLiveServer, this));
}

void LiveServer::localLiveServer()
{
    //TODO
    isRunning = true;
    const unsigned int WIDTH = (FPS==25?640:320);
    const unsigned int HEIGHT = (FPS==25?480:240);
    const unsigned int MEMSIZE = WIDTH*HEIGHT;
    const unsigned int THUMBWIDTH = WIDTH/4;
    const unsigned int THUMBHEIGHT = HEIGHT/4;
    const unsigned int THUMBMEMSIZE = THUMBWIDTH*THUMBHEIGHT;
    const unsigned int TOTALCAMS = 24;
    try
    {
        using namespace boost::asio::ip;
        boost::asio::io_service ios;
        tcp::acceptor m_LiveAcceptor(ios, tcp::endpoint(tcp::v4(), LIVEPORT));
        isInit = false;
        TRACE(1, "%s: Live Server is Ready.\n", HOSTNAME);
        while(isRunning)
        {
            tcp::iostream cmdStream;
            m_LiveAcceptor.accept(*cmdStream.rdbuf());
            TRACE(1, "%s: Live connection accepted.\n", HOSTNAME);

            std::string initCmd;
            std::getline(cmdStream,initCmd);
            if(initCmd=="INIT")
            {
                std::vector<IplImage *> fullipl(TOTALCAMS);
                std::vector<IplImage *> thumbipl(TOTALCAMS);
                for(unsigned int i=0;i<fullipl.size();i++)
                {
                    fullipl[i] = cvCreateImage(cvSize(WIDTH, HEIGHT),IPL_DEPTH_8U,1);
                    thumbipl[i] = cvCreateImage(cvSize(THUMBWIDTH, THUMBHEIGHT),IPL_DEPTH_8U,1);
                    cvZero(fullipl[i]);
                    cvZero(thumbipl[i]);
                }
                cmdStream << "REDY" << std::endl;
                for(std::string line;std::getline(cmdStream,line);)
                {
                    if(line.empty() || line[0]=='\r')
                    {
                        continue;
                    }
                    std::istringstream iss(line);
                    std::string liveCmd;
                    iss>>liveCmd;
                    int watchingIdx;
                    if(liveCmd=="IDLE")
                    {
                        //DO NOTHING
                    }
                    else
                    {
                        IplImage *pIpl[TOTALCAMS];
                        for(unsigned int i=0;i<TOTALCAMS;i++)
                        {
                            pIpl[i] = cvCreateImageHeader(cvSize(WIDTH, HEIGHT),IPL_DEPTH_8U,1);
                        }
                        PF_EZImage *pfimg = m_Capture->getLiveImg();
                        for(unsigned int i=0;i<TOTALCAMS;i++)
                        {
                            pIpl[i]->imageData = (char *)pfimg->imageArray[i];
                        }
                        for(unsigned int i=0;i<fullipl.size();i++)
                        {
                            cvCopy(pIpl[i],fullipl[i]);
                        }
                        IplImage *coloripl = cvCreateImage(cvSize(WIDTH, HEIGHT),IPL_DEPTH_8U,3);
                        IplImage *colorthumbipl = cvCreateImage(cvSize(THUMBWIDTH, THUMBHEIGHT),IPL_DEPTH_8U,3);
                        for(unsigned int i=0;i<fullipl.size();i++)
                        {
                            cvReleaseImageHeader(&(pIpl[i]));
                            cvCvtColor(fullipl[i],coloripl,CV_BayerGR2RGB);
                            cvResize(coloripl,colorthumbipl);
                            cvCvtColor(colorthumbipl,thumbipl[i],CV_RGB2GRAY);
                        }
                        cvReleaseImage(&coloripl);
                        cvReleaseImage(&colorthumbipl);
                        timestamp_t ts = PFCMU::get_timestamp(fullipl[0]->imageData);
                        if(liveCmd=="THMW")
                        {
                            watchingIdx = 0;
                            iss >> watchingIdx;
                            if(watchingIdx<0 || watchingIdx>23)
                            {
                                watchingIdx = 0;
                            }
                            for(unsigned int i=0;i<fullipl.size();i++)
                            {
                                char thumbbuf[1024];
                                snprintf(thumbbuf,sizeof(thumbbuf),"THUM %d %d %d\n",THUMBWIDTH,THUMBHEIGHT,i);
                                cmdStream << thumbbuf;
                                uint32_t thumbts = htobe32(uint32_t(ts));
                                *(reinterpret_cast<uint32_t *>(thumbipl[i]->imageData)) = thumbts;
                                cmdStream.write(reinterpret_cast<const char *>(thumbipl[i]->imageData), THUMBMEMSIZE);
                            }
                            cmdStream << "FULL\n"
                                    << WIDTH << "\n"
                                    << HEIGHT << "\n"
                                    << watchingIdx << "\n"
                                    <<std::flush;
                            cmdStream.write(reinterpret_cast<const char *>(fullipl[watchingIdx]->imageData), MEMSIZE);
                        }//THMW
                        else if(liveCmd=="THUM")
                        {
                            for(unsigned int i=0;i<fullipl.size();i++)
                            {
                                cmdStream << "THUM\n"
                                        << THUMBWIDTH << "\n"
                                        << THUMBHEIGHT << "\n"
                                        << i << "\n"
                                        << std::flush;
                                uint32_t thumbts = htobe32(uint32_t(ts));
                                *(reinterpret_cast<uint32_t *>(thumbipl[i]->imageData)) = thumbts;
                                cmdStream.write(reinterpret_cast<const char *>(thumbipl[i]->imageData), THUMBMEMSIZE);
                            }
                        }//THUM
                    }//except IDLE

                }//for(std::string line;std::getline(cmdStream,line);)
            }//after INIT
        }//while(isRunning)

    }
    catch (std::exception& e)
    {
        //std::cerr << e.what() << std::endl;
    }
}

bool LiveServer::checkRunning() const
{
    return (isRunning && !isInit);
}
